home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 43 / Amiga Format CD43 (1999)(Future Publishing)(GB)(Track 1 of 2)[!][issue 1999-09].iso / -serious- / archivers / checkx / sources / checkx.c next >
C/C++ Source or Header  |  1999-06-14  |  53KB  |  1,768 lines

  1. #define NAME         "CheckX"
  2. #define REVISION     "57"
  3. #define DISTRIBUTION "(Freeware) "
  4.  
  5. /*
  6. When someone uses the here shown methods for own programs, he has to
  7. contact me first and always to mention me in his program documentation!
  8.  
  9. This program scans for crunched, linked files and archived files. It
  10. decrunches them and saves the result files to another directory-tree.
  11. The scanning routines are recursiv and thus check really all stuff. Linked
  12. files are saved with .1, .2, ... additions.
  13.  
  14. The main purpose it was written for is to scan for crunched files and to
  15. test the decrunch routines. So the logging may take some more time, but is
  16. very stable, as the last log-entry is always the file which possibly
  17. crashed the machine.
  18.  
  19. Address crunched programs are decrunched as well, but not saved. Use
  20. xfdDecrunch or xfdDecrunchAddr to generate decrunched executable files
  21. of this type (with correct header information).
  22.  
  23. CheckX cannot scan files, which are read-protected. You get CheckX error 4
  24. as result in that case. Unprotect files and scan again when you want.
  25.  
  26. NOTE: SaveDir must exist already, only sub-dirs are created.
  27.  
  28. The program must be compiled and linked without startup-code. You can set
  29. the pure file protection bit and make it resident, because it is multi-
  30. reentrant (no global variables, except library bases).
  31. This means it can be called multiple times as well, but this is not
  32. recommended, as said above CheckX needs lots of memory.
  33.  
  34. Disk archives are handled this way:
  35. They are unarchived to RD0: in depth1, to RD1: in depth2 (when archive is
  36. in RD0:) and to RD2: in depth3, ....
  37.  
  38. NOTE: accessing RD0:, RD1 or RD2: during this time may produce errors.
  39. This includes starting CheckX twice, when scanning disk archives. For high
  40. density archives the archive names are RH1:, RH2:, ...
  41.  
  42. Splitted DMS-Archives may produce strange errors, but can be checked
  43. correctly, when the two parts are directly after another (e.g. no other
  44. track archive is between them). In this case the first file shows some
  45. XPKCERR_READWRITE and the second one the correct stuff.
  46.  
  47. Crypted archives are not supported yet (e.g. asking for password).
  48. */
  49.  
  50. /* Programmheader
  51.  
  52.     Name:        CheckX
  53.     Author:        SDI
  54.     Distribution:    Freeware
  55.     Description:    scans and decrunches crunched files with xfd
  56.     Compileropts:    -
  57.     Linkeropts:    -l xpkmaster xadmaster amiga -gsi
  58.  
  59.  1.0   14.12.96 : first Version
  60.  1.1   28.12.96 : moved PassRequest into xpkmaster.library
  61.  1.2   12.02.97 : now also decrunches Exe-Files
  62.  1.3   15.06.97 : added length output as test
  63.  1.4   21.11.97 : renamed from Decrunch, got really new program
  64.  1.5   22.11.97 : bug-fixes
  65.  1.6   29.11.97 : added unarchiving feature
  66.  1.7   30.11.97 : bug-fixes
  67.  1.8   06.12.97 : xpkmaster.library now only required with ASKPWD option
  68.  1.9   07.12.97 : Added archive copy for weird archive names, better error
  69.     codes
  70.  1.10  08.12.97 : fixed error codes a bit
  71.  1.11  11.12.97 : disabled DOS requests, added Zip-Archives, added TaskID
  72.     to temporary filenames
  73.  1.12  12.12.97 : added Arc, ZOO and LhASFX archives
  74.  1.13  13.12.97 : fixed Arc recognition
  75.  1.14  19.12.97 : deletes copied arc before scan
  76.  1.15  22.12.97 : crunched archives are unarchived correctly now
  77.  1.16  02.01.98 : opens dos.library itself, no startup-code required
  78.  1.17  23.01.98 : added disk crunchers
  79.  1.18  24.01.98 : some fixes
  80.  1.19  01.02.98 : little bug-fix in argument-option use
  81.  1.20  06.02.98 : better error output, added automount
  82.  1.21  08.02.98 : little bug-fix
  83.  1.22  10.02.98 : fixed archive copy conditions, added PRINTALL
  84.  1.23  12.02.98 : fixed help text, bug fixes with unlinking and FreeMem
  85.  1.24  13.02.98 : added unstripping
  86.  1.25  04.03.98 : added PRINTEXEC
  87.  1.26  13.03.98 : added high density DMS support
  88.  1.27  19.03.98 : added LOUD keyword
  89.  1.28  23.03.98 : RDx no longer depends on archive depth, but on dddepth
  90.  1.29  10.04.98 : bug fixes
  91.  1.30  26.04.98 : bug fixes
  92.  1.31  09.05.98 : now uses no longer adress 4 for SysBase
  93.  1.32  31.05.98 : better output
  94.  1.33  04.06.98 : added HEADER addition for address files
  95.  1.34  08.08.98 : bug fix with SAVE
  96.  1.35  24.09.98 : added xvs.library virus checks
  97.  1.36  18.10.98 : xvs is opened global and only once
  98.  1.37  30.10.98 : renamed from CheckXFD
  99.  1.38  11.11.98 : fixed format drive bug using a delay and an error report
  100.  1.39  14.11.98 : format error with AUTOMOUNT removed
  101.  1.40  16.11.98 : removed HEADER addition stuff
  102.  1.41  18.11.98 : better RDx: access and mount
  103.  1.42  23.11.98 : fixed bug with hunk stripping
  104.  1.43  29.12.98 : now prints an error, when virus detection is turned off,
  105.     added time calculation and output
  106.  1.44  31.12.98 : little bug fix
  107.  1.45  06.02.99 : bug fixes, added xadmaster.library stuff, removed LOUD
  108.     and internal DMS call
  109.  1.46  09.02.99 : removed internal LZX call
  110.  1.47  11.02.99 : now uses assembler startcode allocating a bigger stack
  111.  1.48  14.02.99 : bug-fixes for nocylinder archivers (PackDev)
  112.  1.49  16.02.99 : fixed strip option (don't know, where the error was :-)
  113.  1.50  21.02.99 : removed internal Zoom call and disk-archiver stuff
  114.  1.51  22.02.99 : fixed archiver call for remaining non-XAD archivers, added
  115.     empty file check
  116.  1.52  23.02.99 : fixed StartCode return value
  117.  1.53  24.02.99 : forgot empty check for archived files
  118.  1.54  08.03.99 : old archiver calling did not work, when file was XAD
  119.     unarchived
  120.  1.55  26.03.99 : prints error, when logfile cannot be created
  121.  1.56  30.03.99 : added bootblock scanning for unarchived disks
  122.  1.57  16.05.99 : bug fix with unlinked file save
  123. */
  124.  
  125. #include <proto/exec.h>
  126. #include <proto/dos.h>
  127. #include <proto/xfdmaster.h>
  128. #include <proto/xadmaster.h>
  129. #include <proto/xpkmaster.h>
  130. #include <proto/intuition.h>
  131. #include <proto/xvs.h>
  132. #include <libraries/xfdmaster.h>
  133. #include <dos/dostags.h>
  134. #include <dos/doshunks.h>
  135. #include <dos/filehandler.h>
  136. #include <exec/memory.h>
  137. #include "SDI_defines.h" /* make version string */
  138.  
  139. #define SDI_TO_ANSI
  140. #include "SDI_ASM_STD_protos.h"
  141.  
  142. #define PARAM   "FROM,LOG,SAVE/K,ALL/S,ASKPWD/S,AUTOMOUNT/S,PRINTALL/S," \
  143.         "PRINTEXEC/S,"                 \
  144.         "NODECRUNCH/S,NOUNLINK/S,NOUNARCHIVE/S,NOUNTRACK/S,"     \
  145.         "NOTRACKCUT/S,NOSTRIP/S,NOVIRUS/S"
  146.  
  147. #ifdef __SASC
  148.   #define XpkBase    xpkbase
  149.   #define ASSIGN_XPK
  150.   #define IntuitionBase    intuitionbase
  151.   #define ASSIGN_INT
  152. #else
  153.   struct Library *    XpkBase        = 0;
  154.   struct IntuitionBase *IntuitionBase    = 0;
  155.   #define ASSIGN_XPK    XpkBase = xpkbase;
  156.   #define ASSIGN_INT    IntuitionBase = intuitionbase;
  157. #endif
  158. struct xfdMasterBase *    xfdMasterBase    = 0;
  159. struct DosLibrary *    DOSBase        = 0;
  160. struct ExecBase *    SysBase        = 0;
  161. struct xvsBase *    xvsBase        = 0;
  162. struct xadMasterBase *    xadMasterBase    = 0;
  163.  
  164. struct Args {
  165.   STRPTR from;
  166.   STRPTR log;
  167.   STRPTR save;
  168.   ULONG  all;
  169.   ULONG  askpwd;
  170.   ULONG  automount;
  171.   ULONG  printall;
  172.   ULONG  printexec;
  173.   ULONG  nodecrunch;
  174.   ULONG  nounlink;
  175.   ULONG  nounarchive;
  176.   ULONG  nountrack;
  177.   ULONG  notrackcut;
  178.   ULONG  nostrip;
  179.   ULONG  novirus;
  180. };
  181.  
  182. struct CrunchMemList {
  183.   struct CrunchMemList * cml_Next;
  184.   APTR             cml_MemoryRegion;
  185.   ULONG             cml_MemorySize;
  186. };
  187.  
  188. #define CHECKXFLAG_SAVE            (1<< 0)
  189. #define CHECKXFLAG_ALL            (1<< 1)
  190. #define CHECKXFLAG_ASKPWD        (1<< 2)
  191. #define CHECKXFLAG_AUTOMOUNT        (1<< 3)
  192. #define CHECKXFLAG_PRINTALL        (1<< 4)
  193. #define CHECKXFLAG_PRINTEXEC        (1<< 5)
  194. #define CHECKXFLAG_NODECRUNCH        (1<< 6)
  195. #define CHECKXFLAG_NOUNLINK        (1<< 7)
  196. #define CHECKXFLAG_NOUNARCHIVE        (1<< 8)
  197. #define CHECKXFLAG_NOUNTRACK        (1<< 9)
  198. #define CHECKXFLAG_NOTRACKCUT        (1<<10)
  199. #define CHECKXFLAG_NOSTRIP        (1<<11)
  200.  
  201. #define CHECKXFLAG_XVSLIB        (1<<15)
  202. #define CHECKXFLAG_XADLIB        (1<<16)
  203.  
  204. #define CHKXCALLFLAGS    (CHECKXFLAG_SAVE|CHECKXFLAG_ALL|          \
  205.              CHECKXFLAG_ASKPWD|CHECKXFLAG_AUTOMOUNT|      \
  206.              CHECKXFLAG_PRINTALL|CHECKXFLAG_PRINTEXEC|      \
  207.              CHECKXFLAG_NODECRUNCH|CHECKXFLAG_NOUNLINK|   \
  208.              CHECKXFLAG_NOUNARCHIVE|CHECKXFLAG_NOUNTRACK| \
  209.              CHECKXFLAG_NOTRACKCUT|CHECKXFLAG_NOSTRIP|      \
  210.              CHECKXFLAG_XVSLIB|CHECKXFLAG_XADLIB)
  211.  
  212. #define CHKXSAVEFLAGS    (CHECKXFLAG_LINKED|CHECKXFLAG_CRUNCHED|      \
  213.              CHECKXFLAG_STRIPPED)
  214.  
  215. #define CHECKXFLAG_NAMEPRINTED        (1<<20)
  216. #define CHECKXFLAG_CRUNCHED        (1<<21)
  217. #define CHECKXFLAG_LINKED        (1<<22)
  218. #define CHECKXFLAG_ADDRESS        (1<<23)
  219. #define CHECKXFLAG_NOFREEMEM        (1<<24)
  220. #define CHECKXFLAG_STRIPPED        (1<<25)
  221. #define CHECKXFLAG_HIGHDENSITY        (1<<26)
  222. #define CHECKXFLAG_FILEARCHIVED        (1<<27)
  223. #define CHECKXFLAG_DISKARCHIVED        (1<<28)
  224.  
  225. #define XADERR_OFFSET        0x100
  226. #define XFDERR_OFFSET        0x200
  227.  
  228. #define CHKXERR_NOMEMORY    1
  229. #define CHKXERR_EXAMINEERR    2
  230. #define CHKXERR_OPENERR        3
  231. #define CHKXERR_READWRITE    4
  232. #define CHKXERR_SCANERR        5
  233. #define CHKXERR_BREAK        6
  234. #define CHKXERR_OPENDIR        7
  235. #define CHKXERR_NORAD        8
  236. #define CHKXERR_NODOS        9 /* not a dos disk */
  237. #define CHKXERR_RESOURCE    10
  238. #define CHKXERR_NOVIRUS        11
  239. #define CHKXERR_EMPTY        12
  240. #define CHKXERR_NOBOOTVIRUS    13
  241.  
  242. struct FileData {
  243.   struct CrunchMemList * fd_MemList;
  244.   STRPTR         fd_Name;
  245.   ULONG           fd_LogFileFH;
  246.   ULONG           fd_SaveDirL;
  247.   ULONG             fd_Flags;
  248.   ULONG             fd_NumVirus;
  249.   BYTE           fd_RecurseDepth;
  250.   UBYTE           fd_LinkNum;
  251.   UBYTE             fd_ArchiveDepth;
  252.   UBYTE             fd_DDDepth;
  253.   UBYTE             fd_HDDepth;
  254. };
  255.  
  256. LONG DoDirectoryScan(STRPTR, STRPTR, struct FileData *);
  257. LONG DoFileOpen(struct FileData *);
  258. void DoMount(ULONG, ULONG);
  259. BPTR GetRad(struct FileData *, STRPTR);
  260. LONG DoGetVirus(struct FileData *, APTR, ULONG);
  261. LONG DoFileUnArchive(struct FileData *, APTR, ULONG);
  262. LONG DoFileUnLink(struct FileData *, APTR, ULONG);
  263. LONG DoFileUnCrunch(struct FileData *, APTR, ULONG);
  264. LONG DoFileStrip(struct FileData *, APTR, ULONG);
  265. void PrintCHKXFile(struct FileData *);
  266. void PrintCHKXErr(struct FileData *, LONG);
  267. void PrintCHKXTxt(struct FileData *, STRPTR, ...);
  268. LONG AddCrunchMemList(struct FileData *, APTR, ULONG);
  269. void FreeCrunchMemList(struct FileData *, APTR);
  270. LONG SaveUncrFile(struct FileData *, APTR, ULONG);
  271. ULONG OpenParentDir(struct FileData *);
  272. ULONG OpenNewDir(struct FileData *, STRPTR);
  273.  
  274. /* All memory regions must be in mem list. All unneeded memory must be freed
  275.    as fast as possible (after unlinking, decrunching), as well as the
  276.    MemoryList structure.
  277.    
  278.    The program has a loop like scan routine system, which is called for
  279.    every file:
  280.  
  281.    A) Scan files, directories and sub directories and call following for
  282.       every file:
  283.    1) Check for viruses.
  284.    2) Test if it is an archive. When yes decrunch and start with point A.
  285.    3) Test if file is linked. When yes unlink and call point 1 for both
  286.       parts.
  287.    4) Test if file is crunched. When yes, decrunch and start again with
  288.       point 1.
  289.    5) Try stripping useless stuff. When succesful start with point 1 again.
  290.    6) Possibly save file (with SAVE option) or end loop here.
  291. */
  292.  
  293. /* main routine, do argument parsing */
  294. LONG start(void)
  295. {
  296.   LONG error = RETURN_FAIL;
  297.   struct DosLibrary *dosbase;
  298.   struct Process *task;
  299.  
  300.   SysBase = (*((struct ExecBase **) 4));
  301.  
  302.   /* test for WB and reply startup-message */
  303.   if(!(task = (struct Process *) FindTask(0))->pr_CLI)
  304.   {
  305.     WaitPort(&task->pr_MsgPort);
  306.     Forbid();
  307.     ReplyMsg(GetMsg(&task->pr_MsgPort));
  308.     return RETURN_FAIL;
  309.   }
  310.  
  311.   if((dosbase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
  312.   {
  313.     struct xfdMasterBase *xfdmasterbase;
  314.  
  315.     DOSBase = dosbase;
  316.  
  317.     if((xfdmasterbase = (struct xfdMasterBase *)
  318.     OpenLibrary("xfdmaster.library", 37)))
  319.     {
  320.       struct Args Args;
  321.       struct RDArgs *rda;
  322.  
  323.       xfdMasterBase = xfdmasterbase;
  324.  
  325.       memset(&Args, 0, sizeof(struct Args));
  326.  
  327.       if((rda = (struct RDArgs *) AllocDosObject(DOS_RDARGS, 0)))
  328.       {
  329.         rda->RDA_ExtHelp =
  330.         "FROM        source file or directory - may contain patterns\n"
  331.         "LOG         log file name\n"
  332.         "SAVE        directory, where decrunched files are saved\n"
  333.         "ALL         scan deep into directories\n"
  334.         "ASKPWD      ask for password when needed (needs xpkmaster.library)\n"
  335.     "PRINTALL    print all filenames\n"
  336.         "PRINTEXEC   print names of all executable files\n"
  337.     "AUTOMOUNT   automatically mount RDx: device when needed\n"
  338.         "NODECRUNCH  do not decrunch files with xfdmaster\n"
  339.         "NOUNLINK    do not unlink files with xfdmaster\n"
  340.         "NOUNARCHIVE do not call archiver for unarchiving file archives\n"
  341.         "NOUNTRACK   do not call archiver for unarchiving track archives\n"
  342.         "NOTRACKCUT  do not call archiver for partially track archives\n"
  343.         "NOSTRIP     do not strip useless hunks\n"
  344.         "NOVIRUS     do not scan with xvs.library for viruses\n";
  345.         if(ReadArgs(PARAM, (LONG *) &Args, rda))
  346.         {
  347.           ULONG flags = 0, log = 0;
  348.           struct xvsBase *xvsbase = 0;
  349.           struct xadMasterBase *xadmasterbase = 0;
  350.  
  351.           if(!Args.from)    Args.from = "#?";
  352.           if(Args.all)        flags |= CHECKXFLAG_ALL;
  353.           if(Args.save)        flags |= CHECKXFLAG_SAVE;
  354.           if(Args.askpwd)    flags |= CHECKXFLAG_ASKPWD;
  355.           if(Args.automount)    flags |= CHECKXFLAG_AUTOMOUNT;
  356.       if(Args.printall)    flags |= CHECKXFLAG_PRINTALL;
  357.       if(Args.printexec)    flags |= CHECKXFLAG_PRINTEXEC;
  358.           if(Args.nodecrunch)    flags |= CHECKXFLAG_NODECRUNCH;
  359.           if(Args.nounlink)     flags |= CHECKXFLAG_NOUNLINK;
  360.           if(Args.nounarchive)    flags |= CHECKXFLAG_NOUNARCHIVE;
  361.           if(Args.nountrack)    flags |= CHECKXFLAG_NOUNTRACK;
  362.           if(Args.notrackcut)    flags |= CHECKXFLAG_NOTRACKCUT;
  363.           if(Args.nostrip)    flags |= CHECKXFLAG_NOSTRIP;
  364.           if(!Args.novirus)
  365.           {
  366.             if((xvsbase = (struct xvsBase *) OpenLibrary("xvs.library", 33)))
  367.             {
  368.               flags |= CHECKXFLAG_XVSLIB;
  369.               xvsBase = xvsbase;
  370.             }
  371.       }
  372.       if(!Args.nounarchive || !Args.nountrack)
  373.       {
  374.         if((xadmasterbase = (struct xadMasterBase *) OpenLibrary("xadmaster.library", 1)))
  375.         {
  376.           flags |= CHECKXFLAG_XADLIB;
  377.           xadMasterBase = xadmasterbase;
  378.         }
  379.       }
  380.  
  381.           if(!Args.log || (log = Open(Args.log, MODE_READWRITE)))
  382.           {
  383.         struct FileData fd;
  384.         APTR win;
  385.         ULONG s1 = 0, s2 = 0, msecs;
  386.         struct IntuitionBase *intuitionbase;
  387.  
  388.         win = task->pr_WindowPtr;
  389.         task->pr_WindowPtr = (APTR) -1;
  390.         /* prevent dos requests */
  391.  
  392.         if(log)
  393.           SetFileSize(log, 0, OFFSET_BEGINNING);
  394.  
  395.         memset(&fd, 0, sizeof(struct FileData));
  396.             fd.fd_Flags = flags;
  397.             fd.fd_LogFileFH = log;
  398.  
  399.         if(!xvsbase)
  400.         {
  401.           Printf("Virus-Checking disabled!\n");
  402.           if(log)
  403.             FPrintf(log, "Virus-Checking disabled!\n");
  404.         }
  405.  
  406.         if((intuitionbase = (struct IntuitionBase *) OpenLibrary("intuition.library", 37)))
  407.         {
  408.           ASSIGN_INT
  409.           CurrentTime(&s1, &msecs);
  410.         }    
  411.  
  412.         error = DoDirectoryScan(Args.from, Args.save, &fd);
  413.  
  414.         task->pr_WindowPtr = win;
  415.  
  416.         if(intuitionbase)
  417.         {
  418.           CurrentTime(&s2, &msecs);
  419.           s2 -= s1;
  420.           s1 = s2 / 60;
  421.           s2 %= 60;
  422.           msecs = s1 / 60;
  423.           s1 %= 60;
  424.           Printf("\nTime needed for check: %2ld:%02ld:%02ld\n", msecs, s1, s2);
  425.           if(log)
  426.             FPrintf(log, "\nTime needed for check: %2ld:%02ld:%02ld\n", msecs, s1, s2);
  427.           
  428.           CloseLibrary((struct Library *) intuitionbase);
  429.         }
  430.         if(fd.fd_NumVirus)
  431.         {
  432.           Printf("The scan detected %ld virus%s.\n", fd.fd_NumVirus, fd.fd_NumVirus > 1 ? "es" : "");
  433.           if(log)
  434.             FPrintf(log, "The scan detected %ld virus%s.\n", fd.fd_NumVirus, fd.fd_NumVirus > 1 ? "es" : "");
  435.         }
  436.  
  437.             if(log)
  438.               Close(log);
  439.           }
  440.           else if(Args.log)
  441.             Printf("Could not create logfile.\n");
  442.  
  443.       if(xvsbase)
  444.         CloseLibrary((struct Library *) xvsbase);
  445.       if(xadmasterbase)
  446.         CloseLibrary((struct Library *) xadmasterbase);
  447.           FreeArgs(rda);
  448.         }
  449.         FreeDosObject(DOS_RDARGS, rda);
  450.       }
  451.       CloseLibrary((struct Library *) xfdmasterbase);
  452.     }
  453.     CloseLibrary((struct Library *) dosbase);
  454.   }
  455.  
  456.   return (error ? RETURN_FAIL : RETURN_OK);
  457. }
  458.  
  459. /* This scans a directory and calls DoFileOpen for every file. It
  460.    automatically creates SAVE destination directories when necessary. */
  461. LONG DoDirectoryScan(STRPTR name, STRPTR sav, struct FileData *fd)
  462. {
  463.   struct AnchorPath *APath;
  464.   LONG error = CHKXERR_SCANERR;
  465.   ULONG retval;
  466.  
  467.   if(!(fd->fd_Flags & CHECKXFLAG_SAVE) || !sav ||
  468.   (fd->fd_SaveDirL = Lock(sav, SHARED_LOCK)))
  469.   {
  470.     if((APath = (struct AnchorPath *) AllocMem(sizeof(struct AnchorPath) +
  471.     512, MEMF_PUBLIC|MEMF_CLEAR)))
  472.     {
  473.       fd->fd_Name = APath->ap_Buf;
  474.       APath->ap_Strlen = 256;
  475.       for(retval = MatchFirst(name, APath); !retval;
  476.       retval = MatchNext(APath))
  477.       {
  478.         if(APath->ap_Flags & APF_DIDDIR)
  479.         {
  480.           OpenParentDir(fd);
  481.           APath->ap_Flags &= ~APF_DIDDIR; /* clear flag */
  482.         }
  483.         else if(APath->ap_Info.fib_DirEntryType > 0)
  484.         {
  485.           if(fd->fd_Flags & CHECKXFLAG_ALL)
  486.           {
  487.             OpenNewDir(fd, APath->ap_Info.fib_FileName);
  488.             APath->ap_Flags |= APF_DODIR;
  489.           }
  490.         }
  491.         else
  492.         {
  493.           PrintCHKXErr(fd, DoFileOpen(fd));
  494.       fd->fd_Flags &= CHKXCALLFLAGS;
  495.           fd->fd_LinkNum = 0;
  496.  
  497.           while(fd->fd_MemList)
  498.             FreeCrunchMemList(fd, fd->fd_MemList->cml_MemoryRegion);
  499.         }
  500.         if((fd->fd_Flags & CHECKXFLAG_SAVE) && !fd->fd_SaveDirL)
  501.         {
  502.           error = CHKXERR_OPENDIR; break;
  503.         }
  504.         if(CTRL_C)
  505.         {
  506.           error = CHKXERR_BREAK; break;
  507.         }
  508.       }
  509.       MatchEnd(APath);
  510.  
  511.       if(retval == ERROR_NO_MORE_ENTRIES)
  512.         error = 0;
  513.  
  514.       FreeMem(APath, sizeof(struct AnchorPath) + 512);
  515.     }
  516.     else
  517.       error = CHKXERR_NOMEMORY;
  518.  
  519.     if(sav && fd->fd_SaveDirL)
  520.       UnLock(fd->fd_SaveDirL);
  521.   }
  522.   else
  523.     error = CHKXERR_OPENDIR;
  524.  
  525.   return error;
  526. }
  527.  
  528. /* Open a file and call DoGetVirus to scan */
  529. LONG DoFileOpen(struct FileData *fd)
  530. {
  531.   struct FileInfoBlock *fib;
  532.   LONG ret;
  533.  
  534.   if((fib = (struct FileInfoBlock *) AllocDosObject(DOS_FIB, 0)))
  535.   {
  536.     ULONG fh;
  537.  
  538.     if(fd->fd_ArchiveDepth) /* prevent scan errors */
  539.       SetProtection(fd->fd_Name, 0); /* set RWED bits */
  540.     if((fh = Open(fd->fd_Name, MODE_OLDFILE)))
  541.     {
  542.       if(ExamineFH(fh, fib))
  543.       {
  544.         APTR mem;
  545.  
  546.     if(!fib->fib_Size)
  547.           ret = CHKXERR_EMPTY;
  548.         else if((mem = AllocMem(fib->fib_Size, MEMF_ANY)))
  549.         {
  550.           if(Read(fh, mem, fib->fib_Size) != fib->fib_Size)
  551.             ret = CHKXERR_READWRITE;
  552.           else if(!(ret = AddCrunchMemList(fd, mem, fib->fib_Size)))
  553.           {
  554.             if((fd->fd_Flags & CHECKXFLAG_PRINTALL) ||
  555.             ((fd->fd_Flags & CHECKXFLAG_PRINTEXEC) && fib->fib_Size > 4
  556.             && *((ULONG *)mem) == HUNK_HEADER))
  557.               PrintCHKXFile(fd);
  558.             ret = DoGetVirus(fd, mem, fib->fib_Size);
  559.           }
  560.         }
  561.         else
  562.           ret = CHKXERR_NOMEMORY;
  563.       }
  564.       else
  565.         ret = CHKXERR_EXAMINEERR;
  566.       Close(fh);
  567.     }
  568.     else
  569.       ret = CHKXERR_OPENERR;
  570.   
  571.     FreeDosObject(DOS_FIB, fib);
  572.   }
  573.   else
  574.     ret = CHKXERR_NOMEMORY;
  575.  
  576.   return ret;
  577. }
  578.  
  579. /* for SAVE option: open parent directory and try to delete the directory
  580.    we leave. This only succeeds, when the directory is empty. */
  581. ULONG OpenParentDir(struct FileData *fd)
  582. {
  583.   ULONG g;
  584.   UBYTE name[300];
  585.  
  586.   if((g = fd->fd_SaveDirL))
  587.   {
  588.     NameFromLock(g, name, 300);
  589.     fd->fd_SaveDirL = ParentDir(g);
  590.     UnLock(g);
  591.  
  592.     DeleteFile(name);
  593.   }
  594.   else
  595.     return -1;
  596.  
  597.   return fd->fd_SaveDirL;
  598. }
  599.  
  600. /* Open a new subdirectory for SAVE option */
  601. ULONG OpenNewDir(struct FileData *fd, STRPTR name)
  602. {
  603.   ULONG g;
  604.  
  605.   if(fd->fd_SaveDirL)
  606.   {
  607.     g = CurrentDir(fd->fd_SaveDirL);
  608.     if(!(fd->fd_SaveDirL = Lock(name, SHARED_LOCK)))
  609.       if((fd->fd_SaveDirL = CreateDir(name)))
  610.         ChangeMode(CHANGE_LOCK, fd->fd_SaveDirL, SHARED_LOCK);
  611.     UnLock(CurrentDir(g));
  612.   }
  613.   else
  614.     return -1;
  615.  
  616.   return fd->fd_SaveDirL;
  617. }
  618.  
  619. void DoMount(ULONG deep, ULONG hd)
  620. {
  621.   BPTR fh, infh;
  622.   UBYTE buf[50], buf2[60];
  623.  
  624.   sprintf(buf, "T:CheckMountList_%08lx_%03ld", FindTask(0), deep);
  625.  
  626.   if((fh = Open(buf, MODE_NEWFILE)))
  627.   {
  628.     FPrintf(fh,
  629.     "R%lc%ld:\n"
  630.     "\tDevice\t\t= ramdrive.device\n"
  631.     "\tUnit\t\t= %3ld\n"
  632.     "\tSurfaces\t=   2\n"
  633.     "\tBlocksPerTrack\t=  %ld\n"
  634.     "\tReserved\t=   2\n"
  635.     "\tInterleave\t=   0\n"
  636.     "\tLowCyl\t\t=   0\n"
  637.     "\tHighCyl\t\t=  79\n"
  638.     "\tBootPri\t\t= -10\n"
  639.     "\tBuffers\t\t=   5\n"
  640.     "\tBufMemType\t=   1\n#\n", hd ? 'H' : 'D', deep, (hd ? 50 : 10) + deep,
  641.     hd ? 22 : 11);
  642.     Close(fh);
  643.  
  644.     sprintf(buf2, "Mount R%lc%ld: FROM %s", hd ? 'H' : 'D', deep, buf);
  645.     /* I could do this myself, but I don't know, if it is the correct
  646.        method, so I use Mount command. */
  647.     if((infh = Open("NIL:", MODE_OLDFILE)))
  648.     {
  649.       if((fh = Open("NIL:", MODE_NEWFILE)))
  650.       {
  651.         SystemTags(buf2, SYS_Input, infh, SYS_Output, fh, TAG_DONE);
  652.         Close(fh);
  653.       }
  654.       Close(infh);
  655.     }
  656.     DeleteFile(buf);
  657.   }
  658. }
  659.  
  660. /* Try to get RDx: disk and initialize it. */
  661. BPTR GetRad(struct FileData *fd, STRPTR rname)
  662. {
  663.   UBYTE name[20];
  664.  
  665.   sprintf(name, NAME "%03ld", fd->fd_ArchiveDepth);
  666.  
  667.   if(Inhibit(rname, 1))
  668.   {
  669.     Format(rname, name, ID_DOS_DISK);
  670.     Inhibit(rname, 0);
  671.     return Lock(rname, SHARED_LOCK);
  672.   }
  673.   else
  674.   {
  675.     LONG i, m = 0;
  676.     UBYTE name2[20];
  677.     struct DosList *dosl;
  678.     if((dosl = LockDosList(LDF_DEVICES|LDF_READ)))
  679.     {
  680.       i = strlen(rname);
  681.       name2[--i] = 0;
  682.       while(i--)
  683.         name2[i] = rname[i];
  684.       dosl = FindDosEntry(dosl, name2, LDF_DEVICES);
  685.       UnLockDosList(LDF_DEVICES|LDF_READ);
  686.       if(!dosl && (fd->fd_Flags & CHECKXFLAG_AUTOMOUNT))
  687.       {
  688.     DoMount(fd->fd_Flags & CHECKXFLAG_HIGHDENSITY ?
  689.     fd->fd_HDDepth : fd->fd_DDDepth, fd->fd_Flags &
  690.     CHECKXFLAG_HIGHDENSITY);
  691.         m = 1;
  692.       }
  693.       if(dosl || m)
  694.       {
  695.         for(i = 0; i < 50; ++i)
  696.         {
  697.           if(Inhibit(rname, 1))
  698.           {
  699.             Format(rname, name, ID_DOS_DISK);
  700.             Inhibit(rname, 0);
  701.             return Lock(rname, SHARED_LOCK);
  702.           }
  703.           Delay(10);
  704.         }
  705.         /* clear flag if mount failed */
  706.         if(m)
  707.           fd->fd_Flags &= ~CHECKXFLAG_AUTOMOUNT;
  708.       }
  709.     }
  710.   }
  711.  
  712.   return 0;
  713. }
  714.  
  715. LONG DoGetVirus(struct FileData *fd, APTR buffer, ULONG buflength)
  716. {
  717.   if(!buflength) /* restarted with empty file */
  718.     return CHKXERR_EMPTY;
  719.  
  720.   if(fd->fd_Flags & CHECKXFLAG_XVSLIB)
  721.   {
  722.     APTR mem;
  723.       
  724.     if((mem = AllocMem(buflength, MEMF_ANY)))
  725.     {
  726.       struct xvsFileInfo *fi;
  727.       if((fi = (struct xvsFileInfo *) xvsAllocObject(XVSOBJ_FILEINFO)))
  728.       {
  729.         ULONG i;
  730.     /* xvs may modify the buffer! */
  731.         CopyMem(buffer, mem, buflength);
  732.         fi->xvsfi_File = mem;
  733.         fi->xvsfi_FileLen = buflength;
  734.         i = xvsCheckFile(fi);
  735.         if(i == XVSFT_DATAVIRUS)
  736.         {
  737.        PrintCHKXTxt(fd, "Data-Virus '%s'", fi->xvsfi_Name);
  738.        ++fd->fd_NumVirus;
  739.      }
  740.         else if(i == XVSFT_FILEVIRUS)
  741.         {
  742.        PrintCHKXTxt(fd, "File-Virus '%s'", fi->xvsfi_Name);
  743.        ++fd->fd_NumVirus;
  744.      }
  745.         else if(i == XVSFT_LINKVIRUS)
  746.         {
  747.        PrintCHKXTxt(fd, "Link-Virus '%s'", fi->xvsfi_Name);
  748.        ++fd->fd_NumVirus;
  749.      }
  750.         xvsFreeObject(fi);
  751.       }
  752.       else
  753.         PrintCHKXErr(fd, CHKXERR_NOVIRUS);
  754.       FreeMem(mem, buflength);
  755.     }
  756.     else
  757.       PrintCHKXErr(fd, CHKXERR_NOVIRUS);
  758.   }
  759.  
  760.   return DoFileUnArchive(fd, buffer, buflength);
  761. }
  762.  
  763. /****************************************************************************/
  764. /****        old Archive stuff, should become obsolete        *****/
  765. /****************************************************************************/
  766.  
  767. #define ARCTYPE_LHA      1
  768. #define ARCTYPE_ZIP      2
  769. #define ARCTYPE_ZOO      3
  770. #define ARCTYPE_LHA_SFX      4
  771. #define ARCTYPE_ARC      5
  772.  
  773. #define CHECKXFLAG_ARCCOPY        (1<<30)
  774. #define CHECKXFLAG_DIRCHANGE        (1<<31)
  775.  
  776. LONG DoArcNameCheck(struct UnArcData *, STRPTR, ULONG, ULONG,
  777.      struct FileData *);
  778. LONG DeleteAll(STRPTR);
  779.  
  780. struct UnArcData { /* This is allocated to save stack space */
  781.   STRPTR uad_ArcName;
  782.   UBYTE  uad_DestDir[30];
  783.   UBYTE  uad_DoDestDir[30];
  784.   UBYTE  uad_CopyArcName[30];
  785.   UBYTE  uad_Command[200];
  786. };
  787.  
  788. /* Test if we need to copy the archive to a temporary file. This is
  789.    necessary, because most archivers are not able to handle archives
  790.    correctly, when there are pattern characters in the path or archive
  791.    name. Also they fail, when the archive name has an incorrect extension.
  792.  
  793.    For Archivers like Zoo and Arc, which dearchive always to current
  794.    directory, we need to copy always, as the arcname must have an absolute
  795.    path, which is not guarranteed for argument path name, as this may be
  796.    relative to current directory.
  797.    --> except we are already in a decrunched archive, as here the name is
  798.    garanted to be absolute, e.g. start with ':'.
  799.      
  800.    Archives which are crunched with an alien cruncher or are linked must be
  801.    copied as well. (If this really exists ???)
  802.  
  803.    In these cases the archive file is copied with a correct filename and
  804.    extension, so the archiver works well.
  805.    Problem: This needs mem (or disk space when T: is assigned to hard
  806.    disk).
  807. */
  808. LONG DoArcNameCheck(struct UnArcData *uad, STRPTR mem, ULONG buflength,
  809. ULONG arc, struct FileData *fd)
  810. {
  811.   STRPTR p;
  812.   LONG err = 0;
  813.  
  814.   for(p = uad->uad_ArcName; *p; ++p)
  815.   {
  816.     if(*p == '#' || *p == '(' || *p == ')' || *p == '[' || *p == ']'
  817.     || *p == '*' || *p == '~' || *p == '#' || *p == '?' || *p == '|')
  818.       fd->fd_Flags |= CHECKXFLAG_ARCCOPY;
  819.   }
  820.   if((fd->fd_Flags & (CHECKXFLAG_CRUNCHED|CHECKXFLAG_LINKED|CHECKXFLAG_FILEARCHIVED)) ||
  821.   ((fd->fd_Flags & CHECKXFLAG_DIRCHANGE) && !fd->fd_ArchiveDepth))
  822.     fd->fd_Flags |= CHECKXFLAG_ARCCOPY;
  823.   else if(!(fd->fd_Flags & CHECKXFLAG_ARCCOPY))
  824.   {
  825.     if((p -= 4) <= uad->uad_ArcName) /* position of extension */
  826.       p = uad->uad_ArcName+1; /* at least one char as name is needed */
  827.     switch(arc)
  828.     {
  829.     case ARCTYPE_LHA:
  830.       if(stricmp(p, ".lha") && stricmp(p, ".lzh"))
  831.         fd->fd_Flags |= CHECKXFLAG_ARCCOPY;
  832.       break;
  833.     case ARCTYPE_ZIP:
  834.       if(stricmp(p, ".zip")) fd->fd_Flags |= CHECKXFLAG_ARCCOPY;
  835.       break;
  836.     case ARCTYPE_LHA_SFX:
  837.       if(stricmp(p, ".run")) fd->fd_Flags |= CHECKXFLAG_ARCCOPY;
  838.       break;
  839.     case ARCTYPE_ARC:
  840.       if(stricmp(p, ".arc")) fd->fd_Flags |= CHECKXFLAG_ARCCOPY;
  841.       break;
  842.     case ARCTYPE_ZOO:
  843.       if(stricmp(p, ".zoo")) fd->fd_Flags |= CHECKXFLAG_ARCCOPY;
  844.       break;
  845.     }            
  846.   }
  847.   if(fd->fd_Flags & CHECKXFLAG_ARCCOPY)
  848.   {
  849.     ULONG d;
  850.     switch(arc)
  851.     {
  852.     case ARCTYPE_LHA:
  853.       p = ".lha"; break;
  854.     case ARCTYPE_ZIP:
  855.       p = ".zip"; break;
  856.     case ARCTYPE_ZOO:
  857.       p = ".zoo"; break;
  858.     case ARCTYPE_LHA_SFX:
  859.       p = ".run"; break;
  860.     case ARCTYPE_ARC:
  861.       p = ".arc"; break;
  862.     }            
  863.     sprintf(uad->uad_CopyArcName, "T:CheckArc_%08lx_%03ld%s", FindTask(0),
  864.     fd->fd_ArchiveDepth, p);
  865.     uad->uad_ArcName = uad->uad_CopyArcName;
  866.     if((d = Open(uad->uad_ArcName, MODE_NEWFILE)))
  867.     {
  868.       if(Write(d, mem, buflength) != buflength)
  869.         err = CHKXERR_READWRITE;
  870.       Close(d);
  871.     }
  872.     else
  873.       err = CHKXERR_OPENERR;
  874.   }
  875.  
  876.   return err;
  877. }
  878.  
  879. /* Tests if a file is an archive. When yes, the archive is unarchived and
  880.    DoDirectoryScan is called for the result files. Else DoFileUnLink is
  881.    called.
  882. */
  883. LONG DoFileUnArchiveOld(struct FileData *fd, APTR buffer, ULONG buflength)
  884. {
  885.   ULONG arc = 0;
  886.   STRPTR mem = (STRPTR) buffer;
  887.   LONG err = 0;
  888.  
  889.   if(buflength > 7 && mem[2] == '-' && mem[3] == 'l' && mem[4] == 'h'
  890.   && mem[6] == '-')
  891.   { /* This is an LhA-File */
  892.     arc = ARCTYPE_LHA;
  893.     PrintCHKXTxt(fd, "LhA (ARCHIVE)");
  894.   }
  895.   else if(buflength > 4 && mem[0] == 'P' && mem[1] == 'K' && mem[2] == 3
  896.   && mem[3] == 4)
  897.   {
  898.     arc = ARCTYPE_ZIP;
  899.     PrintCHKXTxt(fd, "Zip (ARCHIVE)");
  900.   }
  901.   else if(buflength > 4 && mem[0] == 'Z' && mem[1] == 'O' && mem[2] == 'O'
  902.   && mem[3] == ' ' && mem[5] == '.')
  903.   {
  904.     arc = ARCTYPE_ZOO;
  905.     fd->fd_Flags |= CHECKXFLAG_DIRCHANGE;
  906.     PrintCHKXTxt(fd, "ZOO (ARCHIVE)");
  907.   }
  908.   else if(buflength > 4 && mem[0x2C] == 'S' && mem[0x2D] == 'F' &&
  909.   mem[0x2E] == 'X' && mem[0x2F] == '!' && *((ULONG *)mem) == 0x3F3)
  910.   {
  911.     arc = ARCTYPE_LHA_SFX;
  912.     PrintCHKXTxt(fd, "LhA SFX (ARCHIVE)");
  913.   }
  914.   else if(buflength > 2 && mem[0] == 0x1A && mem[1] && mem[1] < 9)
  915.   { /* This detection is very unsecure !!! */
  916.     arc = ARCTYPE_ARC;
  917.     fd->fd_Flags |= CHECKXFLAG_DIRCHANGE;
  918.     PrintCHKXTxt(fd, "Arc (ARCHIVE)");
  919.   }
  920.  
  921.   if(arc)
  922.   {
  923.     if(!(fd->fd_Flags & CHECKXFLAG_NOUNARCHIVE))
  924.     {
  925.       struct UnArcData *uad;
  926.  
  927.       if((uad = (struct UnArcData *) AllocMem(sizeof(struct UnArcData),
  928.       MEMF_ANY)))
  929.       { /* AllocMem to prevent stack overflow */
  930.  
  931.     uad->uad_ArcName = fd->fd_Name;
  932.     err = DoArcNameCheck(uad, mem, buflength, arc, fd);
  933.  
  934.         FreeCrunchMemList(fd, mem);
  935.         if(!err && !OpenNewDir(fd, FilePart(fd->fd_Name)))
  936.       err = CHKXERR_OPENERR;
  937.         if(!err)
  938.         {
  939.           BPTR destdir, storedir = 0;
  940.  
  941.           sprintf(uad->uad_DestDir, "T:CheckX_%08lx_%03ld",
  942.           FindTask(0), fd->fd_ArchiveDepth);
  943.           sprintf(uad->uad_DoDestDir, "T:CheckX_%08lx_%03ld/#?",
  944.           FindTask(0), fd->fd_ArchiveDepth);
  945.  
  946.           if((destdir = CreateDir(uad->uad_DestDir)))
  947.       {
  948.           ULONG infh;
  949.         ChangeMode(CHANGE_LOCK, destdir, SHARED_LOCK);
  950.         if(fd->fd_Flags & CHECKXFLAG_DIRCHANGE)
  951.               storedir = CurrentDir(destdir);
  952.  
  953.             switch(arc)
  954.         {
  955.         case ARCTYPE_LHA: case ARCTYPE_LHA_SFX:
  956.           sprintf(uad->uad_Command, "Lha -IMmq x \"%s\" %s/",
  957.           uad->uad_ArcName, uad->uad_DestDir);
  958.           break;
  959.         case ARCTYPE_ZIP:
  960.           sprintf(uad->uad_Command, "UnZip \"%s\" -d %s/",
  961.           uad->uad_ArcName, uad->uad_DestDir);
  962.           break;
  963.         case ARCTYPE_ZOO:
  964.           sprintf(uad->uad_Command, "Zoo x//qqq \"%s\"",
  965.           uad->uad_ArcName);
  966.           break;
  967.         case ARCTYPE_ARC:
  968.           sprintf(uad->uad_Command, "Arc xwn \"%s\"",
  969.           uad->uad_ArcName);
  970.           break;
  971.         }
  972.  
  973.         err = CHKXERR_RESOURCE;
  974.  
  975.         if((infh = Open("NIL:", MODE_OLDFILE)))
  976.         {
  977.           ULONG outfh;
  978.               if((outfh = Open("NIL:", MODE_NEWFILE)))
  979.           {
  980.         ULONG i;
  981.  
  982.         if(!(i = SystemTags(uad->uad_Command, SYS_Input, infh,
  983.         SYS_Output, outfh, TAG_DONE)))
  984.               err = 0;
  985.             else if(i != 10 || IoErr() != 205)
  986.             {
  987.           /* special error handling, gets later removed with this function */
  988.               PrintCHKXTxt(fd, "CheckX-Error 20: archiver returned error code");
  989.               err = 0;
  990.             }
  991.                 Close(outfh);
  992.               }
  993.               Close(infh);
  994.             }
  995.           }
  996.       else
  997.         err = CHKXERR_OPENDIR;
  998.  
  999.         if(fd->fd_Flags & CHECKXFLAG_ARCCOPY)
  1000.         { /* save some memory */
  1001.         fd->fd_Flags &= ~CHECKXFLAG_ARCCOPY;
  1002.         DeleteFile(uad->uad_ArcName);
  1003.       }
  1004.       if(destdir)
  1005.       {
  1006.         if(!err)
  1007.         {
  1008.           struct FileData fdp;
  1009.  
  1010.           CopyMem(fd, &fdp, sizeof(struct FileData));
  1011.           fdp.fd_Flags = (fdp.fd_Flags&CHKXCALLFLAGS)|CHECKXFLAG_ALL;
  1012.           ++fdp.fd_ArchiveDepth;
  1013.           ++fdp.fd_RecurseDepth;
  1014.           fdp.fd_MemList = 0;
  1015.           err = DoDirectoryScan(uad->uad_DoDestDir, 0, &fdp);
  1016.           fd->fd_SaveDirL = fdp.fd_SaveDirL;
  1017.           fd->fd_NumVirus = fdp.fd_NumVirus;
  1018.         }
  1019.  
  1020.         if(fd->fd_Flags & CHECKXFLAG_DIRCHANGE)
  1021.           CurrentDir(storedir);
  1022.         UnLock(destdir);
  1023.         DeleteAll(uad->uad_DestDir);
  1024.       }
  1025.  
  1026.           if(!OpenParentDir(fd))
  1027.         err = CHKXERR_OPENDIR;
  1028.         }
  1029.       if(fd->fd_Flags & CHECKXFLAG_ARCCOPY)
  1030.       DeleteFile(uad->uad_ArcName);
  1031.  
  1032.         FreeMem(uad, sizeof(struct UnArcData));
  1033.       }
  1034.       else
  1035.         err = CHKXERR_NOMEMORY;
  1036.     }
  1037.   }
  1038.   else
  1039.     err = DoFileUnLink(fd, buffer, buflength);
  1040.  
  1041.   return err;
  1042. }
  1043.  
  1044. /* This deletes a temporary directory and all files in it.
  1045.    It returns 0 on error and gets name of directory to delete.
  1046. */
  1047. LONG DeleteAll(STRPTR name)
  1048. {
  1049.   LONG retval;
  1050.   struct AnchorPath *APath;
  1051.   STRPTR fname;
  1052.  
  1053.   if((APath = (struct AnchorPath *) AllocMem(sizeof(struct AnchorPath) +
  1054.   512, MEMF_PUBLIC|MEMF_CLEAR)))
  1055.   {
  1056.     APath->ap_Strlen = 256;
  1057.  
  1058.     fname = (STRPTR) APath->ap_Buf + 256;
  1059.     for(retval = MatchFirst(name, APath); !retval; retval = MatchNext(APath))
  1060.     {
  1061.       if(*fname)
  1062.       {
  1063.         SetProtection(fname, 0); /* set RWED bits */
  1064.         DeleteFile(fname);
  1065.       }
  1066.  
  1067.       CopyMem(APath->ap_Buf, fname, 256);
  1068.  
  1069.       if(APath->ap_Flags & APF_DIDDIR)
  1070.         APath->ap_Flags &= ~APF_DIDDIR; /* clear flag */
  1071.       else if(APath->ap_Info.fib_DirEntryType > 0) /* a directory */
  1072.       {
  1073.         APath->ap_Flags |= APF_DODIR; *fname = 0;
  1074.       }
  1075.     }
  1076.     MatchEnd(APath);
  1077.  
  1078.     FreeMem(APath, sizeof(struct AnchorPath) + 512);
  1079.   }
  1080.  
  1081.   return DeleteFile(name); /* when this returns error, then any of the
  1082.   above functions may have failed --> directory not empty. */
  1083. }
  1084.  
  1085. LONG CheckBoot(struct FileData *fd, STRPTR drivename)
  1086. {
  1087.   LONG err = CHKXERR_NOBOOTVIRUS;
  1088.  
  1089.   if(fd->fd_Flags & CHECKXFLAG_XVSLIB)
  1090.   {
  1091.     struct DosList *dsl;
  1092.     if((dsl = LockDosList(LDF_DEVICES|LDF_READ)))
  1093.     {
  1094.       if((dsl = FindDosEntry(dsl, drivename, LDF_DEVICES)))
  1095.       {
  1096.       struct FileSysStartupMsg *fssm;
  1097.  
  1098.         fssm = (struct FileSysStartupMsg *) BADDR(dsl->dol_misc.dol_handler.dol_Startup);
  1099.         if((LONG) fssm > 200)
  1100.         {
  1101.           struct DosEnvec *denv;
  1102.           denv = ((struct DosEnvec *) BADDR(fssm->fssm_Environ));
  1103.  
  1104.           /* test if the entry is a correct fssm -> check for valid data */
  1105.           if(denv && denv->de_TableSize < 64 && !(denv->de_SizeBlock &
  1106.           0x127) && (denv->de_LowCyl <= denv->de_HighCyl))
  1107.           {
  1108.         struct MsgPort *mp;
  1109.  
  1110.         if((mp = CreateMsgPort()))
  1111.         {
  1112.               struct IOStdReq *req;
  1113.  
  1114.           if((req = (struct IOStdReq *) CreateIORequest(mp, sizeof(struct IOStdReq))))
  1115.           {
  1116.                 if(!OpenDevice(((STRPTR)(fssm->fssm_Device<<2))+1, fssm->fssm_Unit, (struct IORequest *)req, 0))
  1117.                 {
  1118.               APTR mem;
  1119.       
  1120.               if((mem = AllocMem(1024, MEMF_ANY)))
  1121.               {
  1122.               req->io_Command = CMD_READ;
  1123.             req->io_Length = 1024;
  1124.             req->io_Data = mem;
  1125.          /* req->io_Offset = 0 */;
  1126.               if(!DoIO((struct IORequest *)req))
  1127.               {
  1128.               struct xvsBootInfo *bi;
  1129.                     if((bi = (struct xvsBootInfo *) xvsAllocObject(XVSOBJ_BOOTINFO)))
  1130.                     {
  1131.                 bi->xvsbi_Bootblock = mem;
  1132.             err = 0;
  1133.                 if(xvsCheckBootblock(bi) == XVSBT_VIRUS)
  1134.                 {
  1135.               PrintCHKXTxt(fd, "Boot-Virus '%s'", bi->xvsbi_Name);
  1136.               ++fd->fd_NumVirus;
  1137.              }
  1138.                 xvsFreeObject(bi);
  1139.                     }
  1140.                   }
  1141.                   FreeMem(mem, 1024);
  1142.                 }
  1143.               CloseDevice((struct IORequest *) req);
  1144.             }
  1145.                 DeleteIORequest(req);
  1146.               }
  1147.               DeleteMsgPort(mp);
  1148.             }
  1149.           }
  1150.         }
  1151.       }
  1152.       UnLockDosList(LDF_DEVICES|LDF_READ);
  1153.     }
  1154.   }
  1155.   else
  1156.     err = 0;
  1157.  
  1158.   return err;
  1159. }
  1160.  
  1161. /****************************************************************************/
  1162.  
  1163. /* Tests if a file is an archive. When yes, the archive is unarchived and
  1164.    DoDirectoryScan is called for the result files. Else DoFileUnLink is
  1165.    called.
  1166. */
  1167. LONG DoFileUnArchive(struct FileData *fd, APTR buffer, ULONG buflength)
  1168. {
  1169.   LONG err = 0;
  1170.  
  1171.   if(fd->fd_Flags & CHECKXFLAG_XADLIB)
  1172.   {
  1173.     struct xadArchiveInfo *ai;
  1174.  
  1175.     if((ai = (struct xadArchiveInfo *) xadAllocObject(XADOBJ_ARCHIVEINFO, 0)))
  1176.     {
  1177.       if(!xadGetInfo(ai, XAD_INMEMORY, buffer, XAD_INSIZE, buflength,
  1178.       TAG_DONE))
  1179.       {
  1180.     STRPTR arcname;
  1181.     
  1182.     arcname = fd->fd_Name;
  1183.  
  1184.         if(ai->xai_Flags & XADAIF_FILECORRUPT)
  1185.           PrintCHKXTxt(fd, "%s (ARCHIVE, CORRUPTED)", ai->xai_Client->xc_ArchiverName);
  1186.         else
  1187.           PrintCHKXTxt(fd, "%s (ARCHIVE)", ai->xai_Client->xc_ArchiverName);
  1188.         
  1189.         if(!(!(fd->fd_Flags & CHECKXFLAG_NOUNARCHIVE) && ai->xai_FileInfo ||
  1190.         !(fd->fd_Flags & CHECKXFLAG_NOUNTRACK) && ai->xai_DiskInfo))
  1191.           err = DoFileUnArchiveOld(fd, buffer, buflength); /* later DoFileUnLink */
  1192.         else if(!OpenNewDir(fd, FilePart(fd->fd_Name)))
  1193.       err = CHKXERR_OPENERR;
  1194.     else
  1195.     {
  1196.       if(!(fd->fd_Flags & CHECKXFLAG_NOUNARCHIVE) && ai->xai_FileInfo)
  1197.       {
  1198.         struct xadFileInfo *fi;
  1199.         fi = ai->xai_FileInfo;
  1200.         while(!CTRL_C && fi)
  1201.         {
  1202.           APTR dest;
  1203.           
  1204.           if(!(fi->xfi_Flags & (XADFIF_DIRECTORY|XADFIF_LINK)))
  1205.           {
  1206.                 ULONG flags;
  1207.  
  1208.                 flags = fd->fd_Flags;
  1209.                 fd->fd_Flags &= ~CHECKXFLAG_NAMEPRINTED;
  1210.                 fd->fd_Flags |= CHECKXFLAG_FILEARCHIVED;
  1211.                 fd->fd_Name = fi->xfi_FileName;
  1212.                 fd->fd_RecurseDepth++;
  1213.                 fd->fd_ArchiveDepth++;
  1214.                 if(!fi->xfi_Size)
  1215.                   err = CHKXERR_EMPTY;
  1216.             else if((dest = AllocMem(fi->xfi_Size, MEMF_PUBLIC)))
  1217.             {
  1218.               if(!(err = AddCrunchMemList(fd, dest, fi->xfi_Size)))
  1219.               {
  1220.                     if((err = xadFileUnArc(ai, XAD_OUTMEMORY, dest, XAD_OUTSIZE,
  1221.                     fi->xfi_Size, XAD_ENTRYNUMBER, fi->xfi_EntryNumber, TAG_DONE)))
  1222.                       err += XADERR_OFFSET;
  1223.                     else
  1224.                     {
  1225.                       if((fd->fd_Flags & CHECKXFLAG_PRINTALL) ||
  1226.                       ((fd->fd_Flags & CHECKXFLAG_PRINTEXEC) && fi->xfi_Size > 4
  1227.                       && *((ULONG *)dest) == HUNK_HEADER))
  1228.                         PrintCHKXFile(fd);
  1229.                       err = DoGetVirus(fd, dest, fi->xfi_Size);
  1230.                     }
  1231.                     FreeCrunchMemList(fd, dest);
  1232.                   }
  1233.                   else
  1234.                     FreeMem(dest, fi->xfi_Size);
  1235.             }
  1236.             else
  1237.               err = CHKXERR_NOMEMORY;
  1238.  
  1239.             if(err)
  1240.             {
  1241.               PrintCHKXErr(fd, err);
  1242.               err = 0;
  1243.             }
  1244.                 --fd->fd_RecurseDepth;
  1245.                 --fd->fd_ArchiveDepth;
  1246.                 fd->fd_Flags = flags;
  1247.           }
  1248.           fi = fi->xfi_Next;
  1249.         }
  1250.       }
  1251.       if(!(fd->fd_Flags & CHECKXFLAG_NOUNTRACK) && ai->xai_DiskInfo)
  1252.       {
  1253.         struct DiskInfoData {
  1254.           UBYTE name[10];
  1255.           UBYTE buf[50];
  1256.           BPTR destdir;
  1257.           ULONG geom;
  1258.         } *d;
  1259.  
  1260.         /* reduce stacksize, as we have a recursive program */
  1261.         if((d = AllocMem(sizeof(struct DiskInfoData), MEMF_PUBLIC)))
  1262.         {
  1263.           struct xadDiskInfo *di;
  1264.           di = ai->xai_DiskInfo;
  1265.  
  1266.           while(!CTRL_C && di)
  1267.           {
  1268.             if(di->xdi_SectorSize != 512 || (di->xdi_TrackSectors != 11 &&
  1269.             di->xdi_TrackSectors != 22) || (!(di->xdi_Flags & XADDIF_NOHEADS) &&
  1270.             di->xdi_Heads != 2) || (!(di->xdi_Flags & XADDIF_NOCYLINDERS) &&
  1271.             di->xdi_Cylinders != 80))
  1272.             {
  1273.               sprintf(d->buf, "-disk image %ld (unsupported geometry)", di->xdi_EntryNumber);
  1274.               d->geom = 1;
  1275.             }
  1276.             else
  1277.             {
  1278.               d->geom = 0;
  1279.               if(di->xdi_TrackSectors == 11)
  1280.                     sprintf(d->name, "RD%ld:", fd->fd_DDDepth);
  1281.               else
  1282.               {
  1283.                 fd->fd_Flags |= CHECKXFLAG_HIGHDENSITY;
  1284.                     sprintf(d->name, "RH%ld:", fd->fd_HDDepth);
  1285.                   }
  1286.  
  1287.           if(!(di->xdi_Flags & (XADDIF_NOHIGHCYL|XADDIF_NOLOWCYL)) &&
  1288.           (di->xdi_LowCyl || di->xdi_HighCyl != 79))
  1289.                 sprintf(d->buf, "-disk image %ld (%s, %ld to %ld)",
  1290.                 di->xdi_EntryNumber, fd->fd_Flags & CHECKXFLAG_HIGHDENSITY ?
  1291.                 "HD" : "DD", di->xdi_LowCyl, di->xdi_HighCyl);
  1292.               else
  1293.                 sprintf(d->buf, "-disk image %ld (%s)",
  1294.                 di->xdi_EntryNumber, fd->fd_Flags & CHECKXFLAG_HIGHDENSITY ?
  1295.                 "HD" : "DD");
  1296.             }
  1297.           
  1298.             fd->fd_Name = d->buf;
  1299.                 PrintCHKXFile(fd);
  1300.  
  1301.             if(di->xdi_TextInfo)
  1302.             {
  1303.               struct xadTextInfo *ti;
  1304.               ULONG flags, i = 1;
  1305.  
  1306.           for(ti = di->xdi_TextInfo; ti; ti = ti->xti_Next)
  1307.           {
  1308.             if(ti->xti_Size && ti->xti_Text)
  1309.             {
  1310.                       flags = fd->fd_Flags;
  1311.                       fd->fd_Flags &= ~CHECKXFLAG_NAMEPRINTED;
  1312.                       fd->fd_Flags |= CHECKXFLAG_NOFREEMEM|CHECKXFLAG_DISKARCHIVED;
  1313.                       fd->fd_RecurseDepth++;
  1314.                       sprintf(d->buf, "--infotext %ld (size %ld)", i, ti->xti_Size);
  1315.                       if((fd->fd_Flags & CHECKXFLAG_PRINTALL) ||
  1316.                       ((fd->fd_Flags & CHECKXFLAG_PRINTEXEC) && ti->xti_Size > 4
  1317.                       && *((ULONG *)(ti->xti_Text)) == HUNK_HEADER))
  1318.                         PrintCHKXFile(fd);
  1319.                       PrintCHKXErr(fd, DoGetVirus(fd, ti->xti_Text, ti->xti_Size));
  1320.                       --fd->fd_RecurseDepth;
  1321.                       fd->fd_Flags = flags;
  1322.                     }
  1323.                     ++i;
  1324.                   }
  1325.             }
  1326.  
  1327.             if(!d->geom)
  1328.             {
  1329.               if((di->xdi_LowCyl == 0 && di->xdi_HighCyl == 79) ||
  1330.               !(fd->fd_Flags & CHECKXFLAG_NOTRACKCUT) ||
  1331.               (di->xdi_Flags & XADDIF_NOCYLINDERS))
  1332.           {
  1333.                     if((d->destdir = GetRad(fd, d->name)))
  1334.                     {
  1335.               struct xadDeviceInfo *dvi;
  1336.  
  1337.                   UnLock(d->destdir);
  1338.  
  1339.                   if((dvi = (struct xadDeviceInfo *)
  1340.                   xadAllocObjectA(XADOBJ_DEVICEINFO, 0)))
  1341.                   {
  1342.                     d->name[strlen(d->name)-1] = 0;
  1343.                     dvi->xdi_DOSName = d->name;
  1344.                     if(!(err = xadDiskUnArc(ai, XAD_OUTDEVICE, dvi,
  1345.                 XAD_ENTRYNUMBER, di->xdi_EntryNumber, XAD_VERIFY,
  1346.                 TRUE, TAG_DONE)) && !di->xdi_LowCyl)
  1347.                   PrintCHKXErr(fd, CheckBoot(fd, d->name));
  1348.                     xadFreeObjectA(dvi, 0);
  1349.                     d->name[strlen(d->name)] = ':';
  1350.                   }
  1351.                   else
  1352.                     err = CHKXERR_NOMEMORY;
  1353.  
  1354.               if(err)
  1355.               {
  1356.                 PrintCHKXErr(fd, XADERR_OFFSET+err); err = 0;
  1357.               }
  1358.               else if(!(d->destdir = Lock(d->name, SHARED_LOCK)))
  1359.                         PrintCHKXErr(fd, CHKXERR_NODOS);
  1360.                       else
  1361.                       {
  1362.                     struct FileData fdp;
  1363.  
  1364.                     CopyMem(fd, &fdp, sizeof(struct FileData));
  1365.                     fdp.fd_Flags = (fdp.fd_Flags&CHKXCALLFLAGS)|CHECKXFLAG_ALL;
  1366.                     fdp.fd_MemList = 0;
  1367.                 fdp.fd_ArchiveDepth++;
  1368.                 fdp.fd_RecurseDepth++;
  1369.                     if(fd->fd_Flags & CHECKXFLAG_HIGHDENSITY)
  1370.                       ++fdp.fd_HDDepth;
  1371.                     else
  1372.                       ++fdp.fd_DDDepth;
  1373.  
  1374.                       PrintCHKXErr(fd, DoDirectoryScan(d->name, 0, &fdp));
  1375.                       fd->fd_SaveDirL = fdp.fd_SaveDirL;
  1376.                       fd->fd_NumVirus = fdp.fd_NumVirus;
  1377.                       UnLock(d->destdir);
  1378.                       }
  1379.                     }
  1380.                     else
  1381.                       PrintCHKXErr(fd, CHKXERR_NORAD);
  1382.               }
  1383.             }
  1384.             fd->fd_Flags &= ~CHECKXFLAG_HIGHDENSITY;
  1385.             di = di->xdi_Next;
  1386.           } /* while */
  1387.           FreeMem(d, sizeof(struct DiskInfoData));
  1388.         } /* AllocMem DiskInfoData */
  1389.         else
  1390.           err = CHKXERR_NOMEMORY;
  1391.       } /* is there is disk entry? */
  1392.           if(!OpenParentDir(fd))
  1393.             err = CHKXERR_OPENDIR;
  1394.     }
  1395.     
  1396.     fd->fd_Name = arcname;
  1397.       }
  1398.       else
  1399.         err = DoFileUnArchiveOld(fd, buffer, buflength); /* later DoFileUnLink */
  1400.  
  1401.       xadFreeObjectA(ai, 0);
  1402.     }
  1403.     else
  1404.       err = CHKXERR_NOMEMORY;
  1405.   }
  1406.   else
  1407.     err = DoFileUnArchiveOld(fd, buffer, buflength); /* later DoFileUnLink */
  1408.  
  1409.   return err;
  1410. }
  1411.  
  1412. /* Tries to unlink a file. When the file was linked, we call DoGetVirus
  1413.    for the two parts to check if they may be archives, else we call
  1414.    DoFileUnCrunch.
  1415. */
  1416. LONG DoFileUnLink(struct FileData *fd, APTR buffer, ULONG buflength)
  1417. {
  1418.   LONG ret = CHKXERR_NOMEMORY;
  1419.   struct xfdLinkerInfo *xli;
  1420.  
  1421.   if((xli = (struct xfdLinkerInfo *) xfdAllocObject(XFDOBJ_LINKERINFO)))
  1422.   {
  1423.     xli->xfdli_Buffer = buffer;
  1424.     xli->xfdli_BufLen = buflength;
  1425.     if(xfdRecogLinker(xli))
  1426.     {
  1427.       PrintCHKXTxt(fd, xli->xfdli_LinkerName);
  1428.       if(fd->fd_Flags & CHECKXFLAG_NOUNLINK)
  1429.         ret = DoFileUnCrunch(fd, buffer, buflength);
  1430.       else if(xfdUnlink(xli))
  1431.       {
  1432.         ULONG flags;
  1433.     fd->fd_Flags |= CHECKXFLAG_LINKED;
  1434.         ++fd->fd_RecurseDepth;
  1435.         ++fd->fd_LinkNum;
  1436.     flags = fd->fd_Flags;
  1437.     fd->fd_Flags |= CHECKXFLAG_NOFREEMEM;
  1438.         PrintCHKXErr(fd, DoGetVirus(fd, xli->xfdli_Save1,
  1439.         xli->xfdli_SaveLen1));
  1440.         fd->fd_Flags = flags; /* CHECKXFLAG_NOFREEMEM is cleared */
  1441.         PrintCHKXErr(fd, DoGetVirus(fd, xli->xfdli_Save2,
  1442.         xli->xfdli_SaveLen2));
  1443.         ret = 0;
  1444.         --fd->fd_RecurseDepth;
  1445.       }
  1446.       else
  1447.         ret = XFDERR_OFFSET + xli->xfdli_Error;
  1448.     }
  1449.     else
  1450.       ret = DoFileUnCrunch(fd, buffer, buflength);
  1451.  
  1452.     xfdFreeObject(xli);
  1453.   }
  1454.   return ret;
  1455. }
  1456.  
  1457. /* Tries to decrunch a file. When it is crunched, we decrunch it and call
  1458.    DoGetVirus to start the loop again. Else we call unstripping.
  1459. */
  1460. LONG DoFileUnCrunch(struct FileData *fd, APTR buffer, ULONG buflength)
  1461. {
  1462.   LONG ret = CHKXERR_NOMEMORY;
  1463.   struct xfdBufferInfo *xbi;
  1464.  
  1465.   if((xbi = (struct xfdBufferInfo *) xfdAllocObject(XFDOBJ_BUFFERINFO)))
  1466.   {
  1467.     xbi->xfdbi_SourceBuffer = buffer;
  1468.     xbi->xfdbi_SourceBufLen = buflength;
  1469.     xbi->xfdbi_Flags = XFDFF_RECOGEXTERN;
  1470.     if(xfdRecogBuffer(xbi))
  1471.     {
  1472.       struct Library *xpkbase;
  1473.       STRPTR buf = 0;
  1474.       ULONG buflen = 0;
  1475.  
  1476.       PrintCHKXTxt(fd, xbi->xfdbi_PackerFlags & XFDPFF_ADDR ? "%s (ADDRESS)" :
  1477.       "%s", xbi->xfdbi_PackerName);
  1478.  
  1479.       if(fd->fd_Flags & CHECKXFLAG_ASKPWD && (xpkbase =
  1480.       OpenLibrary(XPKNAME, 4)))
  1481.       {
  1482.     ASSIGN_XPK
  1483.         if(xbi->xfdbi_PackerFlags & XFDPFF_PASSWORD)
  1484.         {
  1485.           buflen = (xbi->xfdbi_MaxSpecialLen == 0xFFFF) ? 256 :
  1486.         xbi->xfdbi_MaxSpecialLen;
  1487.           if((buf = (STRPTR) AllocMem(buflen, MEMF_ANY|MEMF_CLEAR)))
  1488.       {
  1489.             if(!XpkPassRequestTags(XPK_PasswordBuf, buf,
  1490.             XPK_PassBufSize, buflen, TAG_DONE))
  1491.           xbi->xfdbi_Special = buf;
  1492.       }
  1493.         }
  1494.         else if(xbi->xfdbi_PackerFlags & XFDPFF_KEY16)
  1495.         {
  1496.       if(!XpkPassRequestTags(XPK_Key16BitPtr, &buflen, TAG_DONE))
  1497.         xbi->xfdbi_Special = &buflen;
  1498.         }
  1499.         else if(xbi->xfdbi_PackerFlags & XFDPFF_KEY32)
  1500.         {
  1501.       if(!XpkPassRequestTags(XPK_Key32BitPtr, &buflen, TAG_DONE))
  1502.             xbi->xfdbi_Special = &buflen;
  1503.         }
  1504.     CloseLibrary(xpkbase);
  1505.       }
  1506.       if(fd->fd_Flags & CHECKXFLAG_NODECRUNCH)
  1507.         ret = DoFileStrip(fd, buffer, buflength);
  1508.       else if(xfdDecrunchBuffer(xbi))
  1509.       {
  1510.         if((xbi->xfdbi_PackerFlags & XFDPFF_ADDR) &&
  1511.         !(fd->fd_Flags & CHECKXFLAG_ADDRESS))
  1512.         {
  1513.       fd->fd_Flags |= CHECKXFLAG_ADDRESS;
  1514.           PrintCHKXErr(fd, SaveUncrFile(fd, buffer, buflength));
  1515.         }
  1516.     fd->fd_Flags |= CHECKXFLAG_CRUNCHED;
  1517.         FreeCrunchMemList(fd, buffer);
  1518.         ++fd->fd_RecurseDepth;
  1519.         if(!(ret = AddCrunchMemList(fd, xbi->xfdbi_TargetBuffer,
  1520.         xbi->xfdbi_TargetBufLen)))
  1521.         {
  1522.           PrintCHKXErr(fd, DoGetVirus(fd, xbi->xfdbi_TargetBuffer,
  1523.             xbi->xfdbi_TargetBufSaveLen));
  1524.         }
  1525.         --fd->fd_RecurseDepth;
  1526.       }
  1527.       else
  1528.         ret = XFDERR_OFFSET + xbi->xfdbi_Error;
  1529.  
  1530.       if(buf)
  1531.         FreeMem(buf, buflen);
  1532.     }
  1533.     else
  1534.       ret = DoFileStrip(fd, buffer, buflength);
  1535.  
  1536.     xfdFreeObject(xbi);
  1537.   }
  1538.   return ret;
  1539. }
  1540.  
  1541. /* Tries to strip useless hunks in a file. When there are some, we remove
  1542.    them and call DoGetVirus to start the loop again. Else we finish.
  1543.    When either unlinking or uncrunching happend in before loops, we may
  1544.    save the file when there was SAVE option.
  1545. */
  1546. LONG DoFileStrip(struct FileData *fd, APTR buffer, ULONG buflength)
  1547. {
  1548.   LONG ret = 0;
  1549.   ULONG reslength = buflength;
  1550.  
  1551.   if(*((ULONG *) buffer) == 0x000003F3 && !(fd->fd_Flags &
  1552.   CHECKXFLAG_NOSTRIP))
  1553.     xfdStripHunks(buffer, buflength, &reslength,
  1554.     XFDSHF_NAME|XFDSHF_SYMBOL|XFDSHF_DEBUG);
  1555.     /* errors are not interpreted */
  1556.  
  1557.   if(buflength > reslength)
  1558.   {
  1559.     fd->fd_Flags |= CHECKXFLAG_STRIPPED;
  1560.     PrintCHKXTxt(fd, "%ld bytes stripped", buflength-reslength);
  1561.     ret = DoGetVirus(fd, buffer, reslength);
  1562.   }
  1563.   else if(!(fd->fd_Flags & CHECKXFLAG_ADDRESS))
  1564.     ret = SaveUncrFile(fd, buffer, buflength);
  1565.  
  1566.   FreeCrunchMemList(fd, buffer);
  1567.  
  1568.   return ret;
  1569. }
  1570.  
  1571. /* Print file name */
  1572. void PrintCHKXFile(struct FileData *fd)
  1573. {
  1574.   STRPTR name = fd->fd_Name;
  1575.   UBYTE i;
  1576.  
  1577.   if(fd->fd_ArchiveDepth) /* skip that ugly T:CheckX.. or RD?: */
  1578.   {
  1579.     if(*name == 'R' && (name[1] == 'D' || name[1] == 'H'))
  1580.     {
  1581.       while(*name != ':')
  1582.         ++name;
  1583.       ++name;
  1584.     }
  1585.     else if(*name == 'T' && name[1] == ':')    /* becomes obsolete with Archive stuff remove */
  1586.     {
  1587.       while(*name != '/')
  1588.         ++name;
  1589.       ++name;
  1590.     }
  1591.   }
  1592.  
  1593.   if(fd->fd_LogFileFH)
  1594.   {
  1595.     for(i = 0; i < fd->fd_ArchiveDepth; ++i)
  1596.       FPutC(fd->fd_LogFileFH, '*');
  1597.     FPrintf(fd->fd_LogFileFH, "%s\n", name);
  1598.   }
  1599.   for(i = 0; i < fd->fd_ArchiveDepth; ++i)
  1600.     FPutC(Output(), '*');
  1601.   Printf("%s\n", name);
  1602.   fd->fd_Flags |= CHECKXFLAG_NAMEPRINTED;
  1603. }
  1604.  
  1605. /* Print Error - Error 100 and up are CheckX special errors. */
  1606. void PrintCHKXErr(struct FileData *fd, LONG err)
  1607. {
  1608.   if(err)
  1609.   {
  1610.     STRPTR txt = 0, txt2;
  1611.  
  1612.     if(err > XFDERR_OFFSET)
  1613.     {
  1614.       txt2 = "XFD-Error %ld: %s";
  1615.       err -= XFDERR_OFFSET;
  1616.       txt = xfdGetErrorText(err);
  1617.     }
  1618.     else if(err > XADERR_OFFSET)
  1619.     {
  1620.       txt2 = "XAD-Error %ld: %s";
  1621.       err -= XADERR_OFFSET;
  1622.       txt = xadGetErrorText(err);
  1623.     }
  1624.     else
  1625.     {
  1626.       txt2 = "CheckX-Error %ld: %s";
  1627.       switch(err)
  1628.       {
  1629.       case CHKXERR_NOMEMORY:    txt = "not enough memory";            break;
  1630.       case CHKXERR_EXAMINEERR:    txt = "examining failed";            break;
  1631.       case CHKXERR_OPENERR:    txt = "opening file failed";            break;
  1632.       case CHKXERR_READWRITE:    txt = "read or write failed";            break;
  1633.       case CHKXERR_SCANERR:    txt = "directory scan failed";            break;
  1634.       case CHKXERR_BREAK:    txt = "user break";                break;
  1635.       case CHKXERR_OPENDIR:    txt = "opening directory failed";        break;
  1636.       case CHKXERR_NORAD:    txt = "accessing ramdrive failed";        break;
  1637.       case CHKXERR_NODOS:    txt = "not an Amiga DOS disk";            break;
  1638.       case CHKXERR_RESOURCE:    txt = "needed resource not available";        break;
  1639.       case CHKXERR_NOVIRUS:    txt = "could not check for virus";        break;
  1640.       case CHKXERR_EMPTY:    txt = "file is empty";                break;
  1641.       case CHKXERR_NOBOOTVIRUS:    txt = "could not check for bootblock virus";    break;
  1642.       }
  1643.     }
  1644.  
  1645.     PrintCHKXTxt(fd, txt2, err, txt);
  1646.   }
  1647. }
  1648.  
  1649. /* Print type text */
  1650. void PrintCHKXTxt(struct FileData *fd, STRPTR txt, ...)
  1651. {
  1652.   UBYTE i;
  1653.  
  1654.   if(!(fd->fd_Flags & CHECKXFLAG_NAMEPRINTED))
  1655.     PrintCHKXFile(fd);
  1656.   if(fd->fd_LogFileFH)
  1657.   {
  1658.     for(i = 0; i <= fd->fd_RecurseDepth; ++i)
  1659.       FPutC(fd->fd_LogFileFH, ' ');
  1660.     VFPrintf(fd->fd_LogFileFH, txt, &txt+1);
  1661.     FPutC(fd->fd_LogFileFH, '\n');
  1662.     Flush(fd->fd_LogFileFH);
  1663.   }
  1664.   for(i = 0; i <= fd->fd_RecurseDepth; ++i)
  1665.     FPutC(Output(), ' ');
  1666.   VPrintf(txt, &txt+1);
  1667.   FPutC(Output(), '\n');
  1668. }
  1669.  
  1670. /* Add memory to the memory list. */
  1671. LONG AddCrunchMemList(struct FileData *fd, APTR reg, ULONG size)
  1672. {
  1673.   struct CrunchMemList *ml;
  1674.  
  1675.   if((ml = (struct CrunchMemList *) AllocMem(sizeof(struct CrunchMemList),
  1676.   MEMF_ANY)))
  1677.   {
  1678.     ml->cml_Next = fd->fd_MemList;
  1679.     ml->cml_MemoryRegion = reg;
  1680.     ml->cml_MemorySize = size;
  1681.     fd->fd_MemList = ml;
  1682.   }
  1683.   else
  1684.   {
  1685.     FreeMem(reg, size);
  1686.     return CHKXERR_NOMEMORY;
  1687.   }
  1688.   return 0;
  1689. }
  1690.  
  1691. /* Free memory from the memory list. */
  1692. void FreeCrunchMemList(struct FileData *fd, APTR reg)
  1693. {
  1694.   struct CrunchMemList mc, *ml = &mc;
  1695.  
  1696.   if(fd->fd_Flags & CHECKXFLAG_NOFREEMEM)
  1697.     return;
  1698.  
  1699.   for(mc.cml_Next = fd->fd_MemList; ml; ml = ml->cml_Next)
  1700.   {
  1701.     if(ml->cml_Next->cml_MemoryRegion == reg)
  1702.     {
  1703.       struct CrunchMemList *m;
  1704.       m = ml->cml_Next;
  1705.       ml->cml_Next = m->cml_Next;
  1706.       FreeMem(m->cml_MemoryRegion, m->cml_MemorySize);
  1707.       FreeMem(m, sizeof(struct CrunchMemList));
  1708.     }
  1709.   }
  1710.  
  1711.   fd->fd_MemList = mc.cml_Next;
  1712. }
  1713.  
  1714. /* Save file, when SAVE option and file was crunched or linked. */
  1715. LONG SaveUncrFile(struct FileData *fd, APTR buf, ULONG size)
  1716. {
  1717.   BPTR filefh, cd;
  1718.   LONG ret = 0, i = 0;
  1719.   UBYTE name[50];
  1720.   UBYTE nbuf[256];
  1721.  
  1722.   if(!(fd->fd_SaveDirL && (fd->fd_Flags & CHKXSAVEFLAGS)))
  1723.     return 0;
  1724.  
  1725.   sprintf(name, (fd->fd_LinkNum ? "%s.%ld" : "%s"), FilePart(fd->fd_Name),
  1726.   fd->fd_LinkNum++);
  1727.  
  1728.   cd = CurrentDir(fd->fd_SaveDirL);
  1729.  
  1730.   while(!ret && name[i])
  1731.   {
  1732.     for(;name[i] && name[i] != '/'; ++i)
  1733.       nbuf[i] = name[i];
  1734.     if(name[i] == '/')
  1735.     {
  1736.       nbuf[i] = 0;
  1737.       if((filefh = Lock(nbuf, SHARED_LOCK)))
  1738.         UnLock(filefh);
  1739.       else
  1740.       {
  1741.         if((filefh = CreateDir(nbuf)))
  1742.           UnLock(filefh);
  1743.         else
  1744.           ret = CHKXERR_OPENERR;
  1745.       }
  1746.       nbuf[i] = name[i];
  1747.       ++i;
  1748.     }
  1749.   }
  1750.  
  1751.   if(!ret)
  1752.   {
  1753.     if((filefh = Open(name, MODE_NEWFILE)))
  1754.     {
  1755.       if(Write(filefh, buf, size) != size)
  1756.         ret = CHKXERR_READWRITE;
  1757.       Close(filefh);
  1758.     }
  1759.     else
  1760.       ret = CHKXERR_OPENERR;
  1761.   }
  1762.  
  1763.   CurrentDir(cd);
  1764.  
  1765.   return ret;
  1766. }
  1767.  
  1768.